﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Spanner
{
    public partial class UI
    {
        // These functions correspond one-to-one with their JavaScript counterparts.

        public static Expr<string> Ith(Expr<string> x, Expr<int> i)
        {
            return JSExpr<string>("#[#]", x, i);
        }

        public static Expr<string> CharAt(Expr<string> x, Expr<int> i)
        {
            return JSExpr<string>("#.charAt(#)", x, i);
        }

        public static Expr<int> CharCodeAt(Expr<string> x, Expr<int> i)
        {
            return JSExpr<int>("#.charCodeAt(#)", x, i);
        }

        public static Expr<string> Concat(params Expr<string>[] xs)
        {

            return new FmtExpr<string>(
                "Concat",
                new FmtStr("\"\".concat"),
                new FmtParens(xs)
            );
        }

        public static Expr<string> FromCharCode(Expr<int> x)
        {
            return JSExpr<string>("String.fromCharCode(#)", x);
        }

        public static Expr<int> IndexOf(Expr<string> x, Expr<string> y, Expr<int> fromIndex = null)
        {
            return ( ((object)fromIndex) == null
                   ? JSExpr<int>("#.indexOf(#)", x, y)
                   : JSExpr<int>("#.indexOf(#, #)", x, y, fromIndex)
                   );
        }

        public static Expr<int> LastIndexOf(Expr<string> x, Expr<string> y, Expr<int> fromIndex = null)
        {
            return ( ((object)fromIndex) == null
                   ? JSExpr<int>("#.lastIndexOf(#)", x, y)
                   : JSExpr<int>("#.lastIndexOf(#, #)", x, y, fromIndex)
                   );
        }

        public static Expr<int> LocaleCompare(Expr<string> x, Expr<string> y)
        {
            return JSExpr<int>("#.localeCompare(#)", x, y);
        }

        public static Expr<int> Length(Expr<string> x)
        {
            return JSExpr<int>("#.length", x);
        }

        public static Expr<string[]> Match(Expr<string> x, Expr<RegExp> regex)
        {
            return JSExpr<string[]>("#.match(#)", x, regex);
        }

        public static Expr<string[]> Match(Expr<string> x, string pattern)
        {
            return JSExpr<string[]>("#.match(#)", x, (Expr<string>)pattern);
        }

        public static Expr<string> Replace(Expr<string> x, Expr<RegExp> pattern, Expr<string> replacement, Expr<string> flags = null)
        {
            if ((object)flags == null) flags = Undefined<string>();
            return JSExpr<string>("#.replace(#, #, #)", x, pattern, replacement, flags);
        }

        public static Expr<string> Replace(Expr<string> x, Expr<RegExp> pattern, Expr<Fn<string, string>> replacement, Expr<string> flags = null)
        {
            if ((object)flags == null) flags = Undefined<string>();
            return JSExpr<string>("#.replace(#, #, #)", x, pattern, replacement, flags);
        }

        public static Expr<string> Replace(Expr<string> x, Expr<RegExp> pattern, Expr<Fn<string, int, string>> replacement, Expr<string> flags = null)
        {
            if ((object)flags == null) flags = Undefined<string>();
            return JSExpr<string>("#.replace(#, #, #)", x, pattern, replacement, flags);
        }

        public static Expr<string> Replace(Expr<string> x, Expr<RegExp> pattern, Expr<Fn<string, int, string, string>> replacement, Expr<string> flags = null)
        {
            if ((object)flags == null) flags = Undefined<string>();
            return JSExpr<string>("#.replace(#, #, #)", x, pattern, replacement, flags);
        }

        public static Expr<string> Replace(Expr<string> x, Expr<string> pattern, Expr<string> replacement, Expr<string> flags = null)
        {
            if ((object)flags == null) flags = Undefined<string>();
            return JSExpr<string>("#.replace(#, #, #)", x, pattern, replacement, flags);
        }

        public static Expr<string> Replace(Expr<string> x, Expr<string> pattern, Expr<Fn<string, string>> replacement, Expr<string> flags = null)
        {
            if ((object)flags == null) flags = Undefined<string>();
            return JSExpr<string>("#.replace(#, #, #)", x, pattern, replacement, flags);
        }

        public static Expr<string> Replace(Expr<string> x, Expr<string> pattern, Expr<Fn<string, int, string>> replacement, Expr<string> flags = null)
        {
            if ((object)flags == null) flags = Undefined<string>();
            return JSExpr<string>("#.replace(#, #, #)", x, pattern, replacement, flags);
        }

        public static Expr<string> Replace(Expr<string> x, Expr<string> pattern, Expr<Fn<string, int, string, string>> replacement, Expr<string> flags = null)
        {
            if ((object)flags == null) flags = Undefined<string>();
            return JSExpr<string>("#.replace(#, #, #)", x, pattern, replacement, flags);
        }

        public static Expr<int> Search(Expr<string> x, Expr<RegExp> regex)
        {
            return JSExpr<int>("#.search(#)", x, regex);
        }

        public static Expr<int> Search(Expr<string> x, string pattern)
        {
            return JSExpr<int>("#.search(#)", x, (Expr<string>)pattern);
        }

        public static Expr<string> Slice(Expr<string> x, Expr<int> beginSlice, Expr<int> endSlice = null)
        {
            return ( ((object)endSlice) == null
                   ? JSExpr<string>("#.slice(#)", x, beginSlice)
                   : JSExpr<string>("#.slice(#, #)", x, beginSlice, endSlice)
                   );
        }

        public static Expr<string[]> Split(Expr<string> x, Expr<RegExp> sep, Expr<int> maxResults = null)
        {
            return ( ((object)maxResults) == null
                   ? JSExpr<string[]>("#.split(#)", x, sep)
                   : JSExpr<string[]>("#.split(#, #)", x, sep, maxResults)
                   );
        }

        public static Expr<string[]> Split(Expr<string> x, Expr<string> sep, Expr<int> maxResults = null)
        {
            return ( ((object)maxResults) == null
                   ? JSExpr<string[]>("#.split(#)", x, sep)
                   : JSExpr<string[]>("#.split(#, #)", x, sep, maxResults)
                   );
        }

        public static Expr<string> Substr(Expr<string> x, Expr<int> start, Expr<int> length = null)
        {
            return ( ((object)length) == null
                   ? JSExpr<string>("#.substr(#)", x, start)
                   : JSExpr<string>("#.substr(#, #)", x, start, length)
                   );
        }

        public static Expr<string> Substring(Expr<string> x, Expr<int> start, Expr<int> top = null)
        {
            return ( ((object)top) == null
                   ? JSExpr<string>("#.substring(#)", x, start)
                   : JSExpr<string>("#.substring(#, #)", x, start, top)
                   );
        }

        public static Expr<double> ToDouble(Expr<string> x)
        {
            return JSExpr<double>("+#", x);
        }

        public static Expr<int> ToInt(Expr<string> x)
        {
            return JSExpr<int>("+#", x);
        }

        public static Expr<string> ToLocaleLowerCase(Expr<string> x)
        {
            return JSExpr<string>("#.toLocaleLowerCase()", x);
        }

        public static Expr<string> ToLocaleUpperCase(Expr<string> x)
        {
            return JSExpr<string>("#.toLocaleUpperCase()", x);
        }

        public static Expr<string> ToLowerCase(Expr<string> x)
        {
            return JSExpr<string>("#.toLowerCase()", x);
        }

        public static Expr<string> ToUpperCase(Expr<string> x)
        {
            return JSExpr<string>("#.toUpperCase()", x);
        }

        public static Expr<string> Trim(Expr<string> x)
        {
            return JSExpr<string>("#.trim()", x);
        }
    }
}
